#include <string.h>
#include "lm_byte_stream.h"


lmByteStream::lmByteStream(char *p, uint sz)
{
	start = p;
	tmpPos = p;
	endPos = p + sz;
}

lmByteStream::~lmByteStream()
{

}

int lmByteStream::require(int sz)
{
	return ((endPos - tmpPos) >= sz);
}

char lmByteStream::read_1byte()
{
	RETU_CONDX(!require(1), -1);
	return (char)*tmpPos++; 
}

short lmByteStream::read_2byte()
{
	RETU_CONDX(!require(2), -1);

	ushort tvalue;
	char *p = (char*)&tvalue;
	p[1] = *tmpPos++;
	p[0] = *tmpPos++;
	
	return tvalue; 
}

int lmByteStream::read_3byte()
{
	RETU_CONDX(!require(3), -1);
	
	uint tvalue = 0x00;
	char *p = (char*)&tvalue;
	p[2] = *tmpPos++;
	p[1] = *tmpPos++;
	p[0] = *tmpPos++;
	
	return tvalue; 
}

int lmByteStream::read_4byte()
{
	RETU_CONDX(!require(4), -1);

	uint tvalue;
	char *p = (char*)&tvalue;
	p[3] = *tmpPos++;
	p[2] = *tmpPos++;
	p[1] = *tmpPos++;
	p[0] = *tmpPos++;
	
	return tvalue; 
}

int lmByteStream::read_string(string &obuff, uint n)
{
	RETU_CONDX(!require(n), -1);

	obuff.append((char*)tmpPos, n);
	tmpPos += n;

	return 1;
}

int lmByteStream::write_string(string value)
{
    RETU_CONDX(value.length() <= 0, -1);
	
    memcpy(tmpPos, value.data(), value.length());
    tmpPos += value.length();
	return 0;
}

int lmByteStream::read_nbyte(char *obuff, uint n)
{
	RETU_CONDX(!require(n), -1);
	
	memcpy(obuff, tmpPos, n);
	tmpPos += n;
	return 1;
}

llong lmByteStream::read_8byte()
{
   RETU_CONDX(!require(8), -1);
    
    ullong value;
    char* pp = (char*)&value;
	
    pp[7] = *tmpPos++;
    pp[6] = *tmpPos++;
    pp[5] = *tmpPos++;
    pp[4] = *tmpPos++;
    pp[3] = *tmpPos++;
    pp[2] = *tmpPos++;
    pp[1] = *tmpPos++;
    pp[0] = *tmpPos++;
 
    return value;
}

bool lmByteStream::empty()
{
    return !start || (tmpPos >= endPos);
}

int lmByteStream::skip_nbyte(int n)
{
	//printf("--hhh--[%ld]--[%d]--[%d]--\n", endPos - tmpPos, n, require(n));
	RETU_CONDX(!require(n), -1);
	//printf("--ggg--[%p]-[%p]-[%p]-[%ld]---------\n",tmpPos, tmpPos+n,  start, start - (tmpPos+n));
	//RETU_CONDX((tmpPos+n > start), -1);
	//printf("--mmmm---\n");

	tmpPos += n;
	return 0;
}

int lmByteStream::skip_start()
{
	tmpPos = start;
	return 1;
}

int lmByteStream::curr_offset()
{
	return (int)(tmpPos - start);
}

char* lmByteStream::curr_pos()
{
	return tmpPos;
}

char* lmByteStream::start_pos()
{
	return start;
}

int lmByteStream::curr_remain()
{
	return (endPos - tmpPos);
}


int lmByteStream::write_1byte(char v)
{
	RETU_CONDX(!require(1), -1);

	*tmpPos++ = v; 
	return 1;
}

int lmByteStream::write_2byte(ushort v)
{
	RETU_CONDX(!require(2), -1);

	char* tv = (char*)&v;

	*tmpPos++ = tv[1]; 
	*tmpPos++ = tv[0]; 
	return 1;
}

int lmByteStream::write_3byte(uint v)
{
	RETU_CONDX(!require(2), -1);

	char* tv = (char*)&v;

	*tmpPos++ = tv[2]; 
	*tmpPos++ = tv[1]; 
	*tmpPos++ = tv[0]; 
	return 1;
}

int lmByteStream::write_4byte(uint v)
{
	RETU_CONDX(!require(4), -1);

	#if 1
	char* tv = (char*)&v;
	*tmpPos++ = tv[3]; 
	*tmpPos++ = tv[2]; 
	*tmpPos++ = tv[1]; 
	*tmpPos++ = tv[0]; 
	#else
	*tmpPos = v[3]<<24 | v[2]<<16 | v[1]<<8 | v[0];
	#endif
	
	return 1;
}

int lmByteStream::write_8byte(llong value)
{
	RETU_CONDX(!require(8), -1);
    
    char* pp = (char*)&value;
    *tmpPos++ = pp[7];
    *tmpPos++ = pp[6];
    *tmpPos++ = pp[5];
    *tmpPos++ = pp[4];
    *tmpPos++ = pp[3];
    *tmpPos++ = pp[2];
    *tmpPos++ = pp[1];
    *tmpPos++ = pp[0];
	return 0;
}

int lmByteStream::write_nbyte(char *v, uint sz)
{
	RETU_CONDX(!require(sz), -1);

	memcpy(tmpPos, v, sz);
	tmpPos += sz;
	return 1;
}

int lmByteStream::write_nbyte1(char *v, int sz)
{
	RETU_CONDX(!require(sz), -1);

	char *p = tmpPos;
	int i = 0, j = sz;
	for(; i < sz; i++){
		p[i] = v[j--];	
	}
	tmpPos += sz;
	return 0;
}


int lmByteStream::write_nbyte2(char *p, char *v, int sz)
{
	int i = 0, j = sz;
	for(; i < sz; i++){
		p[i] = v[j--];	
	}
	
	return 0;
}


lmBitBuffer::lmBitBuffer(lmByteStream* b)
{
    cb = 0;
    cb_left = 0;
    stream = b;
}

lmBitBuffer::~lmBitBuffer()
{

}

bool lmBitBuffer::empty()
{
	RETU_CONDX(cb_left, false);
    return stream->empty();
}

char lmBitBuffer::read_bit()
{
	RETU_CONDX(empty(), -1);
    if (!cb_left) 
	{
        cb = stream->read_1byte();
        cb_left = 8;
    }
    
    char v = (cb >> (cb_left - 1)) & 0x01;
    cb_left--;
    return v;
}


lmSimpleStream::lmSimpleStream()
{

}

lmSimpleStream::~lmSimpleStream()
{

}

int lmSimpleStream::length()
{
	return data.size();
}

char* lmSimpleStream::bytes()
{
	return (length() > 0) ? &data[0] : NULL;
}

int lmSimpleStream::erase(int size)
{
	RETU_COND_DEF(size <= 0);
	DO_COND_RETU(size > length(), data.clear(), 0);
	data.erase(data.begin(), data.begin() + size);
	return 0;
}

void lmSimpleStream::append(char* bytes, int size)
{
	DO_CONDX(size > 0 && bytes, data.insert(data.end(), bytes, bytes + size));
}

void lmSimpleStream::append(lmSimpleStream* src)
{
	append(src->bytes(), src->length());
}
